package com.xiyuan.smartutils.crypto;



import com.xiyuan.smartutils.reflect.Unsafe;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.Charset;

/****
 * DES 加解密工具
 *
 * @version v1.0.0 @author lgz 2021-8-3 新建与整理
 */
@SuppressWarnings("CharsetObjectCanBeUsed")
public class DES {
    static {
        Unsafe.init();
    }
    
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    public static final String DEFAULT_CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
    
    /***********************************************************************************/
    /************************  加密  ****************************************************/
    /***********************************************************************************/
    private static Cipher getCipher(byte[] keyBytes, String cipherAlgorithm, int model) throws Exception {
        
        DESKeySpec desKeySpec = new DESKeySpec(keyBytes);
        
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        
        IvParameterSpec iv = new IvParameterSpec(keyBytes);
        
        Cipher cipher = Cipher.getInstance(cipherAlgorithm);
        cipher.init(model, secretKey, iv);
        return cipher;
    }
    
    /**
     * 加密
     *
     * @param payload         待加密内容
     * @param keyBytes        加密码
     * @param cipherAlgorithm 加密算法
     * @return 加密结果
     * @throws Exception 异常信息
     */
    public static byte[] encrypt(byte[] payload, byte[] keyBytes, String cipherAlgorithm) throws Exception {
        return getCipher(keyBytes, cipherAlgorithm, Cipher.ENCRYPT_MODE).doFinal(payload);
    }
    
    /**
     * 加密 使用默认算法 DES/CBC/PKCS5Padding
     *
     * @param payload  待加密内容
     * @param keyBytes 加密码
     * @return 加密结果
     * @throws Exception 异常信息
     */
    public static byte[] encrypt(byte[] payload, byte[] keyBytes) throws Exception {
        return encrypt(payload, keyBytes, DEFAULT_CIPHER_ALGORITHM);
    }
    
    
    /***********************************************************************************/
    /************************  解密  ****************************************************/
    /***********************************************************************************/
    
    /**
     * 解密
     *
     * @param payload         待解密内容
     * @param keyBytes        解密码
     * @param cipherAlgorithm 解密算法
     * @return 解密结果
     * @throws Exception 异常
     */
    public static byte[] decrypt(byte[] payload, byte[] keyBytes, String cipherAlgorithm) throws Exception {
        return getCipher(keyBytes, cipherAlgorithm, Cipher.DECRYPT_MODE).doFinal(payload);
    }
    
    /**
     * 解密 默认使用 DES/CBC/PKCS5Padding
     *
     * @param payload  待解密内容
     * @param keyBytes 解密码
     * @return 解密结果
     * @throws Exception 异常
     */
    public static byte[] decrypt(byte[] payload, byte[] keyBytes) throws Exception {
        return getCipher(keyBytes, DEFAULT_CIPHER_ALGORITHM, Cipher.DECRYPT_MODE).doFinal(payload);
    }
    
    
    /**
     * 加密，返回加密后的字符串,并且使用 UTF-8编码
     *
     * @param payload         待加密内容
     * @param key             加密码
     * @param cipherAlgorithm 加密算法
     * @return hex 加密后的字符串
     * @throws Exception 异常信息
     */
    public static String encode(String payload, String key, String cipherAlgorithm) throws Exception {
        Charset charset = DEFAULT_CHARSET;
        return HEX.toString(encrypt(payload.getBytes(charset), key.getBytes(charset), cipherAlgorithm));
    }
    
    /**
     * 加密，返回加密后的字符串,并且使用 UTF-8编码, 默认使用 DES/CBC/PKCS5Padding
     *
     * @param payload 待加密内容
     * @param key     加密码
     * @return hex 加密后的字符串
     * @throws Exception 异常信息
     */
    public static String encode(String payload, String key) throws Exception {
        Charset charset = DEFAULT_CHARSET;
        return HEX.toString(encrypt(payload.getBytes(charset), key.getBytes(charset)));
    }
    
    
    /**
     * 解密，参数为 DES 加密后的hex 内容,并且使用 UTF-8编码
     *
     * @param payload         待解密的hex 字符串
     * @param key             解密密码
     * @param cipherAlgorithm 解密算法
     * @return 解密后的内容
     * @throws Exception 异常
     */
    public static String decode(String payload, String key, String cipherAlgorithm) throws Exception {
        byte[] bytes = HEX.toBytes(payload);
        byte[] keyBytes = key.getBytes(DEFAULT_CHARSET);
        return new String(decrypt(bytes, keyBytes, cipherAlgorithm));
    }
    
    /**
     * 解密,参数为 DES 加密后的hex内容。默认使用 DES/CBC/PKCS5Padding
     *
     * @param payload 待解密的hex 字符串
     * @param key     解密密码
     * @return 解密后的内容
     * @throws Exception 异常
     */
    public static String decode(String payload, String key) throws Exception {
        byte[] bytes = HEX.toBytes(payload);
        byte[] keyBytes = key.getBytes(DEFAULT_CHARSET);
        return new String(decrypt(bytes, keyBytes));
    }
}